/*
 * @desc 表单生成组件
 * @params {Object} config - 表单配置
 * @desc config 配置参数
 * {String} labelWidth - 文字标签宽度 80px
 * {Object} rules - 表单校验规则
 * {Array} items - 表单配置
 * @example type:支持 text、radio、select、cascader、textarea、tree
 * {
 *     labelWidth: '80px',
 *     rules:{...},
 *     items:[
 *          { label: '用户名', type: 'text', name: 'username', props: { // 例如：placeholder:'xxx',type:'password'... } },
            {
                label: '状态',
                type: 'select',
                name: 'state',
                defaultValue: 1,
                options: [
                    { label: '在职', value: 1 },
                    { label: '离职', value: 2 },
                    { label: '试用期', value: 3 },
                ],
                props: { 'placeholder': '请选择' }
            },
 *     ]
 * }
 * @parmas {Object} defaultForm - 编辑时需要将数据渲染到表单上
 * @function submit - 表单校验通过后触发
*/

import { defineComponent, reactive, ref, toRefs, watch, onUpdated } from "vue";
import { ElForm, ElFormItem, ElInput, ElButton, ElRadioGroup, ElRadio, ElSelect, ElOption, ElCascader, ElTree } from 'element-plus'
import 'element-plus/dist/index.css'
import mitt from '@/utils/mitt'

export default defineComponent({
    components: {
        ElForm,
        ElFormItem,
        ElInput,
        ElButton,
        ElRadioGroup,
        ElRadio,
        ElSelect,
        ElOption,
        ElCascader,
        ElTree
    },
    props: {
        config: {
            type: Object,
            required: true
        },
        defaultForm: {
            type: Object
        }
    },
    setup(props, { emit }) {
        let form = reactive({})
        let formRef = ref(null)
        const { config, defaultForm } = toRefs(props)
        // 以下属性不需要响应式
        const { rules, labelWidth } = config.value

        // 初始化 form
        const initForm = () => {
            config.value.items.forEach(item => {
                form[item.name] = item?.defaultValue || ''
            });
        }

        // 监听 form 表单对象如果发生改变则通过 mitt 发布事件，传递最新的值，进行操作
        watch(form, (n, o) => {
            mitt.emit('changeForm', n)
        }, { deep: true })

        watch(defaultForm, (n, o) => {
            if (Object.keys(n).length > 0) {
                form['id'] = n['id']
                Object.keys(n).forEach(item => { form[item] = n[item] });
            } else initForm()
        }, { immediate: true })

        // 校验通过后向外发送提交表单钩子
        const submit = () => {
            formRef.value.validate(state => {
                if (state) mitt.emit('submit', form)
            })
        }

        // 重置表单
        const reset = () => {
            Object.assign(form, defaultForm.value)
        }

        // 清除表单校验信息
        onUpdated(() => {
            formRef.value.clearValidate()
        })

        const createEl = {
            renderText: (d) => {
                return (<el-input v-model={form[d.name]} {...d.props} />)
            },
            renderTextarea(d) {
                return (<el-input v-model={form[d.name]} {...d.props} type='textarea' />)
            },
            renderRadio: (d) => {
                return (
                    <el-radio-group v-model={form[d.name]} {...d.props}>
                        {d.options.map(item => (<el-radio label={item.value} {...item.props}>{item.label}</el-radio>))}
                    </el-radio-group>
                )
            },
            renderSelect: (d) => {
                return (
                    <el-select v-model={form[d.name]} {...d.props}>
                        {d.options.map(item => (<el-option label={item.label} value={item.value} />))}
                    </el-select>
                )
            },
            renderCascader: (d) => {
                return (
                    <el-cascader style="width:100%;" v-model={form[d.name]} {...d.props} />
                )
            },
            renderTree: (d) => {
                return (
                    <el-tree {...d.props} />
                )
            }
        }

        return () => (
            <el-form model={form} rules={rules} label-width={labelWidth} ref={formRef}>
                {config.value.items.map(item => (
                    <el-form-item label={item.label} prop={item.name}>
                        {createEl[`render${item.type.charAt(0).toUpperCase() + item.type.slice(1)}`](item)}
                    </el-form-item>
                ))}
                <el-form-item class="formbtn">
                    <el-button type="primary" onClick={submit}>提交</el-button>
                    <el-button onClick={reset}>重置</el-button>
                </el-form-item>
            </el-form >
        )
    }
})